<template>
	<view :class="['form-item', `form-item--border--${borderModel}`, { 'form-item--hint--model': !hintModel }]">
		<view class="title">
			<view class="required" v-if="requiredPosition == 'left'">
				<v-text v-if="isRequired">*</v-text>
			</view>
			<view v-if="label" class="label">
				{{ label }}
			</view>
			<view class="required" v-if="requiredPosition == 'right'">
				<v-text v-if="isRequired">*</v-text>
			</view>
		</view>
		<view class="control">
			<slot></slot>
			<view class="error-message" v-if="hintModel">
				<v-text v-if="error" type="danger">{{ error }}</v-text>
			</view>
		</view>
		<v-toast ref="toast"></v-toast>
	</view>
</template>

<script lang="ts" setup>
import { ref, inject, onMounted, onUnmounted } from 'vue';
import { getCurrentInstance } from 'vue';

const { proxy } = getCurrentInstance();

const props = defineProps({
	label: {
		type: String,
		default: ''
	},
	name: {
		type: String,
		required: true
	},
	requiredPosition: {
		type: String,
		default: 'right'
	},
	hintModel: {
		type: Boolean,
		default: true
	},
	borderModel: {
		type: String,
		default: 'bottom',
		validator: (v) => ['all', 'none', 'bottom', 'top', 'left', 'right', 'ends', 'up-down'].includes(v)
	}
});

const toast = ref(null);
const error = ref('');
const isRequired = ref(false);
const config = inject('config');
const formContext = inject('form', {
	rules: {},
	formData: {},
	register: (name, validate) => {
		console.log(name, validate);
	},
	unregister: (name) => {
		console.log(name);
	},
	formHasError:{
		value:false
	},
});

const validate = async () => {
	const rules = formContext.rules[props.name] || [];
	const value = formContext.formData[props.name];
	const formData = formContext.formData;

	for (const rule of rules) {
		// 必填校验
		if (rule.required) {
			let isEmpty = false;
			if (value === null || value === undefined || value === '') {
				isEmpty = true;
			} else if (typeof value === 'string' || typeof value === 'number') {
				if (value != null && value !== undefined) {
					isEmpty = !value.toString().trim();
				}
			} else if (Array.isArray(value)) {
				isEmpty = value.length === 0;
			} else if (typeof value === 'object') {
				isEmpty = Object.keys(value).length === 0;
			}
			if (isEmpty) {
				hintModelMessage(rule.message || `${props.label}不能为空`);
				return false;
			}
		}

		// 类型转换校验（非空后执行）
		let processedValue = value;
		if ((rule.type === 'number' || rule.type === 'integer') && value !== null && value !== undefined) {
			processedValue = Number(value);
			if (isNaN(processedValue)) {
				hintModelMessage(rule.message || `${props.label}必须为数字`);
				return false;
			}
			if (rule.type === 'integer' && !Number.isInteger(processedValue)) {
				hintModelMessage(rule.message || `${props.label}必须为整数`);
				return false;
			}
		}

		// 格式校验
		if (value !== null && value !== undefined && value !== '') {
			if (rule.pattern && !rule.pattern.test(value)) {
				hintModelMessage(rule.message || `${props.label}格式错误`);
				return false;
			}

			// 内置类型校验
			if (rule.type === 'email' && !/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(value)) {
				hintModelMessage(rule.message || `请输入有效的邮箱地址`);
				return false;
			}

			if (rule.type === 'mobile' && !/^1[3-9]\d{9}$/.test(value)) {
				hintModelMessage(rule.message || `请输入有效的手机号码`);
				return false;
			}

			// 长度校验
			if (rule.minLength !== undefined && value.length < rule.minLength) {
				hintModelMessage(rule.message || `${props.label}至少需要${rule.minLength}个字符`);
				return false;
			}

			if (rule.maxLength !== undefined && value.length > rule.maxLength) {
				hintModelMessage(rule.message || `${props.label}不能超过${rule.maxLength}个字符`);
				return false;
			}

			// 数值范围校验
			if (typeof rule.min === 'number' && processedValue < rule.min) {
				hintModelMessage(rule.message || `${props.label}不能小于${rule.min}`);
				return false;
			}

			if (typeof rule.max === 'number' && processedValue > rule.max) {
				hintModelMessage(rule.message || `${props.label}不能大于${rule.max}`);
				return false;
			}

			// 关联字段校验（如密码确认）
			if (rule.compareWith) {
				const compareValue = formData[rule.compareWith];
				if (value !== compareValue) {
					hintModelMessage(rule.message || `${props.label}必须与${rule.compareWith}保持一致`);
					return false;
				}
			}

			// 自定义校验函数
			if (rule.validator) {
				const result = await rule.validator(value, formData);
				if (!result) {
					hintModelMessage(rule.message || `${props.label}验证未通过`);
					return false;
				}
			}
		}
	}

	error.value = '';
	return true;
};

const hintModelMessage = (message: string) => {
	if (props.hintModel) {
		error.value = message;
	} else {
		if (formContext && formContext.formHasError.value) {
			return;
		}
		if (toast.value) {
			toast.value.show({
				message: message,
				type: 'error',
				duration: 3000
			});
			formContext.formHasError.value = true;
		}
	}
};

const resetField = () => {
	error.value = '';
	formContext.formData[props.name] = null;
};

// 注册到父表单
onMounted(() => {
	if (formContext && formContext.register) {
		formContext.register(props.name, { validate, resetField });
		if (formContext.rules && formContext.rules[props.name]) {
			isRequired.value = formContext.rules[props.name].some((r) => r.required);
		}
	}
});

onUnmounted(() => {
	if (formContext && formContext.unregister) {
		formContext.unregister(props.name);
	}
});
</script>
<style lang="scss" scoped>
.form-item {
	&--hint--model {
		padding-bottom: 20rpx;
	}

	&--border--all {
		border: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--none {
		border: none;
	}

	&--border--bottom {
		border-bottom: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--top {
		border-top: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--left {
		border-left: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--right {
		border-right: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--ends {
		border-left: 1rpx solid v-bind('config.VFormItem.borderColor');
		border-right: 1rpx solid v-bind('config.VFormItem.borderColor');
	}

	&--border--up-down {
		border-top: 1rpx solid v-bind('config.VFormItem.borderColor');
		border-bottom: 1rpx solid v-bind('config.VFormItem.borderColor');
	}
}
</style>
